package table_walker;

import java.io.BufferedReader;

import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map.Entry;

import DFA.DFA;
import DFA.DFAException;

public class TableWalker {
	private BufferedReader br;
	private int readingKey;
	private DFA dfa;
	private String filename;
	
	public TableWalker(String filename, DFA dfa) throws FileNotFoundException{
		this.filename=filename;
		br=new BufferedReader(new FileReader(filename));
		readingKey=dfa.generateReadingKey();
		this.dfa=dfa;
	}
	
	public List<Token> walk() throws IOException,DFAException{
		List<Token> tokens = new ArrayList<Token>();
		String token = null;
		String tokenText="";
		int c=br.read();
		
		while(c!=-1){
			char in=(char)c;
				try{
					token=dfa.readNext(readingKey, ""+in);
					if(token!=null){
						tokens.add(new Token(token,tokenText));
						tokenText="";
						dfa.resetReading(readingKey);
						continue;
					}
						tokenText+=in;
						c=br.read();
				}
				catch(DFAException exeception){
					if(!Character.isWhitespace(in)){
						throw exeception;
					}
					else{
						c=br.read();
					}
				}	
		}
		token=dfa.readNext(readingKey, "");
		tokens.add(new Token(token,tokenText));
		return tokens;
	}
	
	public List<CompleteToken> find() throws IOException, DFAException{
		
		HashMap<String,CompleteToken> tokens = new HashMap<String,CompleteToken>();
		List<CompleteToken> result=new ArrayList<CompleteToken>();
		String token = null;String temp="";int matchIndexToken=0,matchIndexTemp=0,runningIndex=0;
		String prevtoken="$start";
		String tokenText="";
		int c=br.read(); char in;
		//List<Integer> indexesToken=new ArrayList<Integer>();
 
		while(c!=-1){
			in=(char)c;
			token=dfa.read(readingKey, ""+in);
			if(token==null && prevtoken.equals("$start")){ //Start -> Terminating
				//System.out.println("Restart DFA because it came from Start");
				dfa.resetReading(readingKey);
				tokenText="";
				matchIndexToken=0;
				prevtoken="$start";
				c=br.read();
				runningIndex++;
			}
			else if(token==null && prevtoken.isEmpty()){ // Non-accepting -> terminating
				if(temp.isEmpty()){
					//System.out.println("Restart DFA because it came from Non Accepting");
					dfa.resetReading(readingKey);
					tokenText="";
					matchIndexToken=0;
					prevtoken="$start";
					c=br.read();
					runningIndex++;
				}
				else{
					//System.out.println("Restart DFA and save Temp since its shorter: "+temp);
					if(tokens.containsKey(tokenText)){
						CompleteToken val=tokens.get(tokenText);
						val.getstartIndexes().add(matchIndexTemp);
						tokens.put(tokenText, val);
					}
					else{
						CompleteToken val2=new CompleteToken(temp,filename);
						val2.getstartIndexes().add(matchIndexTemp);
						tokens.put(tokenText, val2);
					}
					//indexesToken.add(matchIndexTemp);
					dfa.resetReading(readingKey);
					tokenText="";
					temp="";
					matchIndexTemp=0;
					matchIndexToken=0;
					prevtoken="$start";
					c=br.read();
					runningIndex++;
				}
			}
			else if(token==null && !prevtoken.equals("$start") && !prevtoken.isEmpty() && prevtoken!=null){ // Accepting -> Terminating
					//System.out.println("Add Token and restart DFA: "+tokenText);
					if(tokens.containsKey(tokenText)){
						CompleteToken val=tokens.get(tokenText);
						val.getstartIndexes().add(runningIndex-matchIndexToken);
						tokens.put(tokenText, val);
					}
					else{
						CompleteToken val2=new CompleteToken(tokenText,filename);
						val2.getstartIndexes().add(runningIndex-matchIndexToken);
						tokens.put(tokenText, val2);
					}
					//indexesToken.add(runningIndex-matchIndexToken);
					dfa.resetReading(readingKey);
					tokenText="";
					matchIndexToken=0;
					prevtoken="$start";
			}
			else if(token.isEmpty() && prevtoken!=null && !prevtoken.equals("$start") && !prevtoken.isEmpty()){ // Accepting -> Non-accepting
				temp=tokenText;
				matchIndexTemp=runningIndex-matchIndexToken;
				tokenText+=in;
				matchIndexToken++;
				c=br.read();
				runningIndex++;
				prevtoken=token;
			}
			else{
				prevtoken=token;
				tokenText+=in;
				matchIndexToken++;
				c=br.read();
				runningIndex++;
			}
		}
		if(token!=null && !token.isEmpty()){
			//System.out.println("Accepting FINAL state, Add token and DONE: "+tokenText);
			if(tokens.containsKey(tokenText)){
				CompleteToken val=tokens.get(tokenText);
				val.getstartIndexes().add(runningIndex-matchIndexToken);
				tokens.put(tokenText, val);
			}
			else{
				CompleteToken val2=new CompleteToken(tokenText,filename);
				val2.getstartIndexes().add(runningIndex-matchIndexToken);
				tokens.put(tokenText, val2);
			}
			//indexesToken.add(runningIndex-matchIndexToken);
		}
		else if(token!=null && token.isEmpty()){
			if(!temp.isEmpty()){
				//System.out.println("Non Accepting FINAL state, Add token and DONE: "+temp);
				if(tokens.containsKey(tokenText)){
					CompleteToken val=tokens.get(tokenText);
					val.getstartIndexes().add(runningIndex-matchIndexToken);
					tokens.put(tokenText, val);
				}
				else{
					CompleteToken val2=new CompleteToken(temp,filename);
					val2.getstartIndexes().add(runningIndex-matchIndexToken);
					tokens.put(tokenText, val2);
				}
//				indexesToken.add(matchIndexTemp);
			}
			else{
				//System.out.println("Non Accepting FINAL state");
			}
		}
		else{
			//System.out.println("Terminating FINAL state");
		}
		
//		System.out.println(indexesToken);
	    Iterator<Entry<String, CompleteToken>> it = tokens.entrySet().iterator();
		while(it.hasNext()){
			Entry<String,CompleteToken> entryToken=(Entry<String, CompleteToken>)it.next();
			result.add(entryToken.getValue());
			//System.out.println(entryToken.getValue().generateList());
		}

			return result;	
		}
}
